package com.conversationboard.view.resultsettable;

import java.io.IOException;
import java.net.URLEncoder;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

import com.conversationboard.formatter.DateFormatter;
import com.conversationboard.model.User;
import com.conversationboard.security.EncryptedKey;
import com.conversationboard.security.EncryptionException;

public class ResultSetTable {

	private List<Link> links = new ArrayList<Link>();
	private static final Pattern dateTime = Pattern.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}", (Pattern.CASE_INSENSITIVE | Pattern.DOTALL));
	private static final Pattern numbers = Pattern.compile("^[0-9]+$", (Pattern.CASE_INSENSITIVE | Pattern.DOTALL));


	public void setLink(int index, String linkTarget, String text, boolean securityKey) {

		Link link = new Link();
		link.setIndex(index);
		link.setLinkTarget(linkTarget);
		link.setText(text);
		link.setSecurityKey(securityKey);

		links.add(link);
	}


	private Link findLink(int index) {

		for (Link link : links) {
			if (link.getIndex() == index) {
				return link;
			}
		}

		return null;
	}


	/**
	 * Note that this function relies on the JDBC driver being relaxed about the types returned from MySQL, in that
	 * it expects to convert them happily to strings. If it becomes stricter, there will need to be metadata examination
	 * to type it.
	 * 
	 * @param headings
	 * @param resultSet
	 * @return
	 * @throws SQLException
	 */

	public String display(User user, String[] headings, ResultSet resultSet, String loginId) throws SQLException, IOException, EncryptionException {

		ResultSetMetaData metaData = resultSet.getMetaData();
		int columns = metaData.getColumnCount();
		StringBuilder buffer = new StringBuilder();

		buffer.append("<table class='table'>");

		buffer.append("<thead>");
		buffer.append("<tr class='header'>");

		for (String heading : headings) {
			buffer.append("<td class='cell'>");
			buffer.append(heading);
			buffer.append("</td>");
		}

		buffer.append("</tr>");
		buffer.append("</thead><tbody>");

		EncryptedKey key = new EncryptedKey();

		while (resultSet.next()) {
			buffer.append("<tr class='row'>");
			for (int i = 1; i <= columns; i++) {
				buffer.append("<td class='cell'>");

				Link link = this.findLink(i);

				if (link != null) {

					buffer.append("<a href='");
					buffer.append(link.getLinkTarget());

					/* If there's already a ? in the link then it's already got a parameter; use an ampersand instead */

					if (link.getLinkTarget().contains("?")) {
						buffer.append("&amp;id=");
					} else {
						buffer.append("?id=");
					}

					String data = resultSet.getString(i);

					if (data == null) {
						data = "";
					}

					/* If it's a date/time, do a substitution */

					if (dateTime.matcher(data).find()) {
						Date date = resultSet.getTimestamp(i);
						String outputDate = DateFormatter.prettyPrint(date, user);
						buffer.append(outputDate);
					} else {
						buffer.append(resultSet.getString(i));
					}

					if (link.isSecurityKey() && (!(loginId == null))) {
						buffer.append("&key=" + URLEncoder.encode(key.getKey(loginId), "UTF-8"));
					}

					buffer.append("'>");

					if (link.getText() != null) {
						buffer.append(link.getText());
					} else {
						buffer.append(resultSet.getString(i));
					}

					buffer.append("</a>");

				} else {

					String data = resultSet.getString(i);

					/* If it's a date/time, do a substitution. If not, it might be a number, format that according to the user's locale */

					if ((data != null) && dateTime.matcher(data).find()) {
						Date date = resultSet.getTimestamp(i);
						String outputDate = DateFormatter.prettyPrintTime(date, user, true, true);
						buffer.append(outputDate);
					} else if ((data != null) && numbers.matcher(data).find()) {
						
						NumberFormat formatter = NumberFormat.getIntegerInstance(user.getLocale());
						
						long number = Long.parseLong(data);
						buffer.append(formatter.format(number));
						
					} else {
						if (data == null) {
							buffer.append("");
						} else {
							buffer.append(resultSet.getString(i));
						}
					}
				}

				buffer.append("</td>");

			}
			buffer.append("</tr>");
		}

		buffer.append("</tbody></table>");

		return buffer.toString();

	}

}
